use semver::VersionReq;
use core::{SourceId, Summary, PackageId};
+use std::rc::Rc;
use util::CargoResult;
-/// Informations about a dependency requested by a Cargo manifest.
+/// The data underlying a Dependency.
#[derive(PartialEq,Clone,Debug)]
-pub struct Dependency {
+pub struct DependencyInner {
name: String,
source_id: SourceId,
req: VersionReq,
only_for_platform: Option<String>,
}
+/// Information about a dependency requested by a Cargo manifest.
+/// Cheap to copy.
+#[derive(PartialEq,Clone,Debug)]
+pub struct Dependency {
+ inner: Rc<DependencyInner>,
+}
+
#[derive(PartialEq, Clone, Debug, Copy)]
pub enum Kind {
Normal,
Build,
}
-impl Dependency {
+impl DependencyInner {
/// Attempt to create a `Dependency` from an entry in the manifest.
pub fn parse(name: &str,
version: Option<&str>,
- source_id: &SourceId) -> CargoResult<Dependency> {
+ source_id: &SourceId) -> CargoResult<DependencyInner> {
let version_req = match version {
Some(v) => try!(VersionReq::parse(v)),
None => VersionReq::any()
};
- Ok(Dependency {
+ Ok(DependencyInner {
only_match_name: false,
req: version_req,
specified_req: version.map(|s| s.to_string()),
- .. Dependency::new_override(name, source_id)
+ .. DependencyInner::new_override(name, source_id)
})
}
- pub fn new_override(name: &str, source_id: &SourceId) -> Dependency {
- Dependency {
+ pub fn new_override(name: &str, source_id: &SourceId) -> DependencyInner {
+ DependencyInner {
name: name.to_string(),
source_id: source_id.clone(),
req: VersionReq::any(),
self.only_for_platform.as_ref().map(|s| &s[..])
}
- pub fn set_kind(mut self, kind: Kind) -> Dependency {
+ pub fn set_kind(mut self, kind: Kind) -> DependencyInner {
self.kind = kind;
self
}
/// Sets the list of features requested for the package.
- pub fn set_features(mut self, features: Vec<String>) -> Dependency {
+ pub fn set_features(mut self, features: Vec<String>) -> DependencyInner {
self.features = features;
self
}
/// Sets whether the dependency requests default features of the package.
- pub fn set_default_features(mut self, default_features: bool) -> Dependency {
+ pub fn set_default_features(mut self, default_features: bool) -> DependencyInner {
self.default_features = default_features;
self
}
/// Sets whether the dependency is optional.
- pub fn set_optional(mut self, optional: bool) -> Dependency {
+ pub fn set_optional(mut self, optional: bool) -> DependencyInner {
self.optional = optional;
self
}
/// Set the source id for this dependency
- pub fn set_source_id(mut self, id: SourceId) -> Dependency {
+ pub fn set_source_id(mut self, id: SourceId) -> DependencyInner {
self.source_id = id;
self
}
/// Set the version requirement for this dependency
- pub fn set_version_req(mut self, req: VersionReq) -> Dependency {
+ pub fn set_version_req(mut self, req: VersionReq) -> DependencyInner {
self.req = req;
self
}
pub fn set_only_for_platform(mut self, platform: Option<String>)
- -> Dependency {
+ -> DependencyInner {
self.only_for_platform = platform;
self
}
/// Lock this dependency to depending on the specified package id
- pub fn lock_to(self, id: &PackageId) -> Dependency {
+ pub fn lock_to(self, id: &PackageId) -> DependencyInner {
assert_eq!(self.source_id, *id.source_id());
assert!(self.req.matches(id.version()));
self.set_version_req(VersionReq::exact(id.version()))
(self.only_match_name || (self.req.matches(id.version()) &&
&self.source_id == id.source_id()))
}
+
+ pub fn into_dependency(self) -> Dependency {
+ Dependency {inner: Rc::new(self)}
+ }
+}
+
+impl Dependency {
+ /// Attempt to create a `Dependency` from an entry in the manifest.
+ pub fn parse(name: &str,
+ version: Option<&str>,
+ source_id: &SourceId) -> CargoResult<Dependency> {
+ DependencyInner::parse(name, version, source_id).map(|di| {
+ di.into_dependency()
+ })
+ }
+
+ pub fn new_override(name: &str, source_id: &SourceId) -> Dependency {
+ DependencyInner::new_override(name, source_id).into_dependency()
+ }
+
+ pub fn clone_inner(&self) -> DependencyInner { (*self.inner).clone() }
+
+ pub fn version_req(&self) -> &VersionReq { self.inner.version_req() }
+ pub fn name(&self) -> &str { self.inner.name() }
+ pub fn source_id(&self) -> &SourceId { self.inner.source_id() }
+ pub fn kind(&self) -> Kind { self.inner.kind() }
+ pub fn specified_req(&self) -> Option<&str> { self.inner.specified_req() }
+
+ /// If none, this dependencies must be built for all platforms.
+ /// If some, it must only be built for the specified platform.
+ pub fn only_for_platform(&self) -> Option<&str> {
+ self.inner.only_for_platform()
+ }
+
+ /// Lock this dependency to depending on the specified package id
+ pub fn lock_to(self, id: &PackageId) -> Dependency {
+ self.clone_inner().lock_to(id).into_dependency()
+ }
+
+ /// Returns false if the dependency is only used to build the local package.
+ pub fn is_transitive(&self) -> bool { self.inner.is_transitive() }
+ pub fn is_build(&self) -> bool { self.inner.is_build() }
+ pub fn is_optional(&self) -> bool { self.inner.is_optional() }
+ /// Returns true if the default features of the dependency are requested.
+ pub fn uses_default_features(&self) -> bool {
+ self.inner.uses_default_features()
+ }
+ /// Returns the list of features that are requested by the dependency.
+ pub fn features(&self) -> &[String] { self.inner.features() }
+
+ /// Returns true if the package (`sum`) can fulfill this dependency request.
+ pub fn matches(&self, sum: &Summary) -> bool { self.inner.matches(sum) }
+
+ /// Returns true if the package (`id`) can fulfill this dependency request.
+ pub fn matches_id(&self, id: &PackageId) -> bool {
+ self.inner.matches_id(id)
+ }
}
#[derive(PartialEq,Clone,RustcEncodable)]
-pub use self::dependency::Dependency;
+pub use self::dependency::{Dependency, DependencyInner};
pub use self::manifest::{Manifest, Target, TargetKind, Profile, LibKind, Profiles};
pub use self::package::{Package, PackageSet};
pub use self::package_id::{PackageId, Metadata};
// Information about the dependencies for a crate, a tuple of:
//
// (dependency info, candidates, features activated)
-type DepInfo = (Rc<Dependency>, Vec<Rc<Summary>>, Vec<String>);
+type DepInfo = (Dependency, Vec<Rc<Summary>>, Vec<String>);
impl Resolve {
fn new(root: PackageId) -> Resolve {
deps_backup: Vec<DepsFrame>,
remaining_candidates: RcVecIter<Rc<Summary>>,
parent: Rc<Summary>,
- dep: Rc<Dependency>,
+ dep: Dependency,
}
/// Recursively activates the dependencies for `top`, in depth-first order,
fn find_candidate(backtrack_stack: &mut Vec<BacktrackFrame>,
cx: &mut Context, remaining_deps: &mut Vec<DepsFrame>,
parent: &mut Rc<Summary>, cur: &mut usize,
- dep: &mut Rc<Dependency>) -> Option<Rc<Summary>> {
+ dep: &mut Dependency) -> Option<Rc<Summary>> {
while let Some(mut frame) = backtrack_stack.pop() {
if let Some((_, candidate)) = frame.remaining_candidates.next() {
*cx = frame.context_backup.clone();
dep.version_req());
let mut msg = msg;
let all_req = semver::VersionReq::parse("*").unwrap();
- let new_dep = dep.clone().set_version_req(all_req);
+ let new_dep = dep.clone_inner().set_version_req(all_req).into_dependency();
let mut candidates = match registry.query(&new_dep) {
Ok(candidates) => candidates,
Err(e) => return e,
#[allow(deprecated)] // connect => join in 1.3
fn resolve_features(&mut self, parent: &Summary, method: &Method)
- -> CargoResult<Vec<(Rc<Dependency>, Vec<String>)>> {
+ -> CargoResult<Vec<(Dependency, Vec<String>)>> {
let dev_deps = match *method {
Method::Everything => true,
Method::Required { dev_deps, .. } => dev_deps,
feature)));
}
}
- ret.push((Rc::new(dep.clone()), base));
+ ret.push((dep.clone(), base));
}
// All features can only point to optional dependencies, in which case
let new_pkgid = try!(PackageId::new(pkg.name(), pkg.version(), &new_src));
let new_summary = pkg.summary().clone().map_dependencies(|d| {
if !d.source_id().is_path() { return d }
- d.set_source_id(registry.clone())
+ d.clone_inner().set_source_id(registry.clone()).into_dependency()
});
let mut new_manifest = pkg.manifest().clone();
new_manifest.set_summary(new_summary.override_id(new_pkgid));
use url::Url;
use core::{Source, SourceId, PackageId, Package, Summary, Registry};
-use core::dependency::{Dependency, Kind};
+use core::dependency::{Dependency, DependencyInner, Kind};
use sources::{PathSource, git};
use util::{CargoResult, Config, internal, ChainError, ToUrl, human};
use util::{hex, Sha256};
name, req, features, optional, default_features, target, kind
} = dep;
- let dep = try!(Dependency::parse(&name, Some(&req),
- &self.source_id));
+ let dep = try!(DependencyInner::parse(&name, Some(&req),
+ &self.source_id));
let kind = match kind.as_ref().map(|s| &s[..]).unwrap_or("") {
"dev" => Kind::Development,
"build" => Kind::Build,
.set_default_features(default_features)
.set_features(features)
.set_only_for_platform(target)
- .set_kind(kind))
+ .set_kind(kind)
+ .into_dependency())
}
/// Actually perform network operations to update the registry
use rustc_serialize::{Decodable, Decoder};
use core::{SourceId, Profiles};
-use core::{Summary, Manifest, Target, Dependency, PackageId, GitReference};
+use core::{Summary, Manifest, Target, Dependency, DependencyInner, PackageId,
+ GitReference};
use core::dependency::Kind;
use core::manifest::{LibKind, Profile, ManifestMetadata};
use core::package_id::Metadata;
fn process_dependencies<F>(cx: &mut Context,
new_deps: Option<&HashMap<String, TomlDependency>>,
mut f: F) -> CargoResult<()>
- where F: FnMut(Dependency) -> Dependency
+ where F: FnMut(DependencyInner) -> DependencyInner
{
let dependencies = match new_deps {
Some(ref dependencies) => dependencies,
}
}.unwrap_or(try!(SourceId::for_central(cx.config)));
- let dep = try!(Dependency::parse(&n,
- details.version.as_ref()
- .map(|v| &v[..]),
- &new_source_id));
+ let dep = try!(DependencyInner::parse(&n,
+ details.version.as_ref()
+ .map(|v| &v[..]),
+ &new_source_id));
let dep = f(dep)
.set_features(details.features.unwrap_or(Vec::new()))
.set_default_features(details.default_features.unwrap_or(true))
- .set_optional(details.optional.unwrap_or(false));
+ .set_optional(details.optional.unwrap_or(false))
+ .into_dependency();
cx.deps.push(dep);
}
use hamcrest::{assert_that, equal_to, contains};
use cargo::core::source::{SourceId, GitReference};
-use cargo::core::dependency::Kind::Development;
+use cargo::core::dependency::Kind::{self, Development};
use cargo::core::{Dependency, PackageId, Summary, Registry};
use cargo::util::{CargoResult, ToUrl};
use cargo::core::resolver::{self, Method};
let source_id = SourceId::for_git(&url, master);
Dependency::parse(name, Some("1.0.0"), &source_id).unwrap()
}
+fn dep_kind(name: &str, kind: Kind) -> Dependency {
+ dep(name).clone_inner().set_kind(kind).into_dependency()
+}
fn registry(pkgs: Vec<Summary>) -> Vec<Summary> {
pkgs
#[test]
fn test_resolving_with_dev_deps() {
let mut reg = registry(vec!(
- pkg!("foo" => ["bar", dep("baz").set_kind(Development)]),
- pkg!("baz" => ["bat", dep("bam").set_kind(Development)]),
+ pkg!("foo" => ["bar", dep_kind("baz", Development)]),
+ pkg!("baz" => ["bat", dep_kind("bam", Development)]),
pkg!("bar"),
pkg!("bat")
));
let res = resolve(pkg_id("root"),
- vec![dep("foo"), dep("baz").set_kind(Development)],
+ vec![dep("foo"), dep_kind("baz", Development)],
&mut reg).unwrap();
assert_that(&res, contains(names(&["root", "foo", "bar", "baz"])));